import 'dart:async';
import 'dart:typed_data';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:jm_flutter_common/jm_flutter_common.dart' hide LogLevel;
import 'package:permission_handler/permission_handler.dart';
import 'model/ble_discovered_device.dart';

export 'model/ble_discovered_device.dart';

enum JmBleEventType {
  connectState, //连接状态
  scanResult, //扫描结果
  scanState, //扫描状态
  bluetoothState, //蓝牙状态
  noSupportBluetooth, //不支持蓝牙
  noPermission; //无权限

  @override
  String toString() {
    switch (this) {
      case JmBleEventType.connectState:
        return "连接状态";
      case JmBleEventType.scanResult:
        return "扫描结果";
      case JmBleEventType.scanState:
        return "扫描状态";
      case JmBleEventType.bluetoothState:
        return "蓝牙状态";
      case JmBleEventType.noSupportBluetooth:
        return "不支持蓝牙";
      case JmBleEventType.noPermission:
        return "无权限";
      default:
        return "未知";
    }
  }
}

class JmBleEvent {
  JmBleEventType type;
  String deviceId;
  bool state;
  dynamic data;
  JmBleEvent(this.type, {this.deviceId = "", this.state = false, this.data});
}

class JmBleNotifyData {
  String deviceId;
  Uint8List data;
  JmBleNotifyData(this.deviceId, this.data);
}

class JmBleCharacteristic {
  BluetoothCharacteristic? notification;
  BluetoothCharacteristic? write;
  BluetoothCharacteristic? read;
  JmBleCharacteristic({this.notification, this.write, this.read});
}

class JmBle {
  static const String tag = "JmBle";

  static bool debug = false; //是否调试

  static bool _initialized = false; //是否初始化
  static bool _isScanning = false; //是否正在扫描
  static final List<ScanResult> _scanResults = []; //扫描结果
  static final _bleDiscoveredDevices = <BleDiscoveredDevice>[]; //扫描结果

  //扫描ble名字前缀
  static String _namePrefix = "";

  static StreamSubscription<BluetoothAdapterState>? _bluetoothStateSubscription; //蓝牙状态监听
  static StreamSubscription<List<ScanResult>>? _scanResultsSubscription; //扫描结果监听
  static StreamSubscription<bool>? _isScanningSubscription; //扫描状态监听

  static String _serviceFullUUID = "00008689-0000-1000-8000-00805F9B34FB";
  static String _serviceShortUUID = "8689";
  static String _readCharacteristicFullUUID = "0000863A-0000-1000-8000-00805F9B34FB";
  static String _readCharacteristicShortUUID = "863A";
  static String _writeCharacteristicFullUUID = "0000863B-0000-1000-8000-00805F9B34FB";
  static String _writeCharacteristicShortUUID = "863B";
  static String _notifyCharacteristicFullUUID = "0000863C-0000-1000-8000-00805F9B34FB";
  static String _notifyCharacteristicShortUUID = "863C";

  static int _minRssi = -80;

  static final Map<String, StreamSubscription<BluetoothConnectionState>> _connectionStateSubscriptionMap = {}; //连接状态监听
  static final List<BluetoothDevice> _connectedDevices = []; //已连接的设备
  static final Map<String, JmBleCharacteristic> _bleCharacteristics = {}; //特征

  static final StreamController<JmBleNotifyData> _notifyDataStreamController = StreamController<JmBleNotifyData>.broadcast();
  static final StreamController<JmBleEvent> _eventStreamController = StreamController<JmBleEvent>.broadcast();

  static final List<String> _needConnectDeviceIds = [];

  static Stream<JmBleNotifyData> get notifyDataStream => _notifyDataStreamController.stream;
  static Stream<JmBleEvent> get eventStream => _eventStreamController.stream;

  static bool get isScanning => _isScanning;

  static Future init() async {
    logd(tag, "初始化");
    if (_initialized) {
      logd(tag, "已经初始化");
      return;
    }

    _initialized = true;

    FlutterBluePlus.setLogLevel(LogLevel.warning, color: false);

    if (await FlutterBluePlus.isSupported == false) {
      logw(tag, "蓝牙不支持");
      _eventStreamController.add(JmBleEvent(JmBleEventType.noSupportBluetooth));
      return;
    }

    if (await initPermission() == false) {
      logw(tag, "权限不足");
      _eventStreamController.add(JmBleEvent(JmBleEventType.noPermission));
      return;
    }

    if (_bluetoothStateSubscription != null) {
      _bluetoothStateSubscription?.cancel();
    }
    if (_scanResultsSubscription != null) {
      _scanResultsSubscription?.cancel();
    }
    if (_isScanningSubscription != null) {
      _isScanningSubscription?.cancel();
    }

    _bluetoothStateSubscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) async {
      logd(tag, "adapterState:$state");
      switch (state) {
        case BluetoothAdapterState.on:
          logd(tag, "蓝牙已打开");
          _eventStreamController.add(JmBleEvent(JmBleEventType.bluetoothState, state: true));
          break;
        case BluetoothAdapterState.off:
          logd(tag, "蓝牙已关闭");
          _eventStreamController.add(JmBleEvent(JmBleEventType.bluetoothState, state: false));
          // if (kIsAndroid) {
          //   FlutterBluePlus.turnOn();
          // }
          break;
        case BluetoothAdapterState.turningOn:
          logd(tag, "蓝牙正在打开");
          break;
        case BluetoothAdapterState.turningOff:
          logd(tag, "蓝牙正在关闭");
          break;
        case BluetoothAdapterState.unknown:
          logd(tag, "蓝牙状态未知");
          break;
        case BluetoothAdapterState.unauthorized:
          logd(tag, "蓝牙未授权");
          _eventStreamController.add(JmBleEvent(JmBleEventType.noPermission));
          break;
        case BluetoothAdapterState.unavailable:
          logd(tag, "蓝牙不可用");
          _eventStreamController.add(JmBleEvent(JmBleEventType.noSupportBluetooth));
          break;
        default:
          logd(tag, "蓝牙状态未知 $state");
          break;
      }
    });

    _scanResultsSubscription = FlutterBluePlus.scanResults.listen((results) {
      //logd(tag, "扫描结果:${results.length}");
      bool update = false;

      for (var result in results) {
        final resultDevice = result.device;
        final resultRssi = result.rssi;
        final resultDeviceName = resultDevice.platformName;
        final resultDeviceId = resultDevice.remoteId.str;

        if (resultRssi >= _minRssi && resultDeviceName.isNotEmpty) {
          //去重
          if (_scanResults.any((element) => element.device.remoteId.str == resultDeviceId)) {
            continue;
          }

          if (_namePrefix.isNotEmpty) {
            if (resultDeviceName.contains(_namePrefix) == false) {
              if (debug) {
                logd(tag, "发现设备:$resultDeviceName, ID:$resultDeviceId, rssi:$resultRssi");
              }

              continue;
            }
          }

          logd(tag, "发现匹配设备:$resultDeviceName, ID:$resultDeviceId, rssi:$resultRssi");
          logd(tag, "_needConnectDeviceIds: $_needConnectDeviceIds");
          update = true;
          _scanResults.add(result);
          _bleDiscoveredDevices.add(BleDiscoveredDevice(
            device: resultDevice,
            rssi: resultRssi,
          ));

          if (_needConnectDeviceIds.contains(resultDeviceId)) {
            logd(tag, "发现需要连接的设备:$resultDeviceName ,ID:$resultDeviceId");
            // if (_connectedDevices.any((element) => element.remoteId.str == resultDeviceId)) {
            //   logd(tag, "已连接设备:$resultDeviceName ,ID:$resultDeviceId");
            //   continue;
            // }

            connectDevice(result.device);
          }
        }
      }

      if (update) {
        _eventStreamController.add(JmBleEvent(JmBleEventType.scanResult, data: _bleDiscoveredDevices));
      }
    }, onError: (e) {
      logw(tag, "Scan Error:$e");
    });

    _isScanningSubscription = FlutterBluePlus.isScanning.listen((state) {
      _isScanning = state;
      if (state) {
        logd(tag, "正在扫描");
      } else {
        logd(tag, "扫描结束");
      }
      _eventStreamController.add(JmBleEvent(JmBleEventType.scanState, state: state));
    });

    _initialized = true;
  }

  //初始化权限
  static Future<bool> initPermission() async {
    logd(tag, "初始化权限");

    //PermissionStatus locationPermission = await Permission.location.request();
    PermissionStatus locationPermission = await Permission.locationWhenInUse.request();
    await Permission.bluetooth.request();
    PermissionStatus bleScan = await Permission.bluetoothScan.request();
    PermissionStatus bleConnect = await Permission.bluetoothConnect.request();

    if (kIsIOS) {
      return true;
    }
    return locationPermission.isGranted && bleScan.isGranted && bleConnect.isGranted;
  }

  static Future<bool> isBluetoothOn() async {
    return await FlutterBluePlus.adapterState.first == BluetoothAdapterState.on;
  }

  static Future<bool> isBluetoothOff() async {
    return await FlutterBluePlus.adapterState.first == BluetoothAdapterState.off;
  }

  static Future<void> turnOnBluetooth({int timeout = 60}) async {
    return await FlutterBluePlus.turnOn(timeout: timeout);
  }

  static void addNeedConnectDevice(String id) {
    if (!_needConnectDeviceIds.contains(id)) {
      logd(tag, "添加需要连接的设备:$id");
      _needConnectDeviceIds.add(id);
    }
  }

  static void removeNeedConnectDevice(String id) {
    if (_needConnectDeviceIds.contains(id)) {
      logd(tag, "移除需要连接的设备:$id");
      _needConnectDeviceIds.remove(id);
    }
  }

  static void setServiceUUID({String? full, String? short}) {
    _serviceFullUUID = full ?? "";
    _serviceShortUUID = short ?? full?.substring(4, 8) ?? "";
  }

  static void setCharacteristicUUID({
    String? readFull,
    String? readShort,
    String? writeFull,
    String? writeShort,
    String? notifyFull,
    String? notifyShort,
  }) {
    _readCharacteristicFullUUID = readFull ?? "";
    _readCharacteristicShortUUID = readShort ?? readFull?.substring(4, 8) ?? "";
    _writeCharacteristicFullUUID = writeFull ?? "";
    _writeCharacteristicShortUUID = writeShort ?? writeFull?.substring(4, 8) ?? "";
    _notifyCharacteristicFullUUID = notifyFull ?? "";
    _notifyCharacteristicShortUUID = notifyShort ?? notifyFull?.substring(4, 8) ?? "";
  }

  ///停止扫描
  static Future stopScan() async {
    logd(tag, "停止扫描");
    await _checkInit();
    await FlutterBluePlus.stopScan();
  }

  ///开始扫描
  static Future startScan({
    String? name,
    int timeout = 15,
    bool androidUsesFineLocation = false,
    int minRssi = -90,
    List<String> withServices = const [],
  }) async {
    await _checkInit();

    if (name != null) {
      _namePrefix = name;
    }

    logd(tag, "开始扫描: $_namePrefix");
    if (!_initialized) {
      logw(tag, "未初始化");
      return;
    }

    if (_isScanning) {
      logd(tag, "正在扫描, 请勿重复扫描");
      return;
    }
    _eventStreamController.add(JmBleEvent(JmBleEventType.scanResult, data: []));
    _scanResults.clear();
    _bleDiscoveredDevices.clear();
    _minRssi = minRssi;

    final value = FlutterBluePlus.adapterStateNow;
    logd(tag, "adapterStateNow:$value");

    final services = withServices.map((e) => Guid(e)).toList();

    await FlutterBluePlus.startScan(
        timeout: Duration(seconds: timeout),
        androidUsesFineLocation: androidUsesFineLocation,
        withServices: services,
        androidScanMode: AndroidScanMode.balanced);
  }

  static int _connectDeviceRetryCount = 0;

  ///连接设备
  static Future connectDevice(BluetoothDevice device) async {
    await _checkInit();
    final deviceId = device.remoteId.str;
    logd(tag, "连接设备:${device.platformName} ,ID:$deviceId, retry: $_connectDeviceRetryCount");

    final oldSubscription = _connectionStateSubscriptionMap[deviceId];
    if (oldSubscription != null) {
      oldSubscription.cancel();
      _connectionStateSubscriptionMap.remove(deviceId);
    }
    final subscription = device.connectionState.listen((BluetoothConnectionState state) async {
      logd(tag, "连接状态更新:${device.platformName} ,ID:$deviceId, $state");
      switch (state) {
        case BluetoothConnectionState.connected:
          //logd(tag, "连接成功");
          _eventStreamController.add(JmBleEvent(JmBleEventType.connectState, deviceId: deviceId, state: true));
          break;
        case BluetoothConnectionState.disconnected:
          //logd(tag, "断开");
          logd(tag, "断开连接:${device.platformName} ,ID:$deviceId");

          _connectedDevices.remove(device);
          _eventStreamController.add(JmBleEvent(JmBleEventType.connectState, deviceId: deviceId, state: false));
          break;
        default:
          logd(tag, "未知状态: $state");
          break;
      }
    });
    _connectionStateSubscriptionMap[deviceId] = subscription;

    try {
      await device.connect(
        timeout: const Duration(seconds: 15),
        autoConnect: false,
      );
      _connectDeviceRetryCount = 0;
      //device.cancelWhenDisconnected(subscription);
      logd(tag, "连接成功:${device.platformName} ,ID:$deviceId");
      _connectedDevices.add(device);
      final services = await device.discoverServices();
      if (services.isEmpty) {
        logw(tag, "未发现服务");
        return;
      }

      for (var service in services) {
        final serviceId = service.uuid.toString();

        if (_uuidMatch(serviceId, full: _serviceFullUUID, short: _serviceShortUUID)) {
          logd(tag, "发现目标服务:${service.uuid}");
          final bleCharacteristic = JmBleCharacteristic();
          _bleCharacteristics[deviceId] = bleCharacteristic;

          for (var characteristic in service.characteristics) {
            logd(tag, "-发现特征:${characteristic.uuid}, properties:${characteristic.properties}");
            bool needCharacteristic = false;

            if (_uuidMatch(characteristic.uuid.toString(), full: _writeCharacteristicFullUUID, short: _writeCharacteristicShortUUID)) {
              if (!characteristic.properties.write && !characteristic.properties.writeWithoutResponse) {
                logw(tag, "写特征不可写 ${characteristic.uuid}");
                continue;
              }
              logd(tag, "发现写特征:${characteristic.uuid}");

              bleCharacteristic.write = characteristic;
              needCharacteristic = true;
            }
            if (_uuidMatch(characteristic.uuid.toString(), full: _notifyCharacteristicFullUUID, short: _notifyCharacteristicShortUUID)) {
              if (!characteristic.properties.notify) {
                logw(tag, "notify特征不可通知 ${characteristic.uuid}");
                continue;
              }
              logd(tag, "发现notify特征:${characteristic.uuid}");

              bleCharacteristic.notification = characteristic;
              characteristic.setNotifyValue(true);
              final notifySubscription = characteristic.lastValueStream.listen((event) {
                final data = Uint8List.fromList(event);
                //logd(tag, "notify收到数据:$deviceId, ${data.toHexString(showLength: true)}");
                _notifyDataStreamController.add(JmBleNotifyData(deviceId, data));
              });

              device.cancelWhenDisconnected(notifySubscription);
              needCharacteristic = true;
            }

            if (needCharacteristic == false) {
              logd(tag, "未知特征:${characteristic.uuid}");
            }
          }
        } else {
          logd(tag, "未知服务:${service.uuid}");
        }
        // for (var characteristic in service.characteristics) {
        //   logd(tag, "发现特征:${characteristic.uuid}");
        // }
      }
    } catch (e) {
      logw(tag, "连接错误: $e");
      final oldSubscription = _connectionStateSubscriptionMap[deviceId];
      if (oldSubscription != null) {
        oldSubscription.cancel();
        _connectionStateSubscriptionMap.remove(deviceId);
      }

      if (_connectDeviceRetryCount < 3) {
        _connectDeviceRetryCount++;
        logd(tag, "连接错误 重试连接次数: $_connectDeviceRetryCount");
        await Future.delayed(const Duration(seconds: 1));
        connectDevice(device);
      } else {
        _connectDeviceRetryCount = 0;
      }
    } finally {}
  }

  ///根据ID断开连接
  static Future<void> disconnectFromId(String id) async {
    final device = _connectedDevices.firstWhereOrNull((element) => element.remoteId.str == id);
    if (device == null) {
      logw(tag, "未找到设备");
      return;
    }
    await disconnect(device);
  }

  ///断开连接
  static Future<void> disconnect(BluetoothDevice device) async {
    final deviceId = device.remoteId.str;

    try {
      logd(tag, "主动断开连接：${device.platformName} ,ID:$deviceId");
      await device.disconnect();
    } catch (e) {
      logw(tag, "Error disconnecting from a device: $e");
    } finally {
      logd(tag, "主动断开连接完成");
      final oldSubscription = _connectionStateSubscriptionMap[deviceId];
      if (oldSubscription != null) {
        oldSubscription.cancel();
        _connectionStateSubscriptionMap.remove(deviceId);
      }
      _connectedDevices.remove(device);
    }
  }

  ///写入数据
  static Future<bool> writeData(
    String id,
    Uint8List data, {
    bool withoutResponse = false,
    bool allowLongWrite = false,
  }) async {
    logd(tag, "写入数据:$id, ${data.toHexString()}");
    final bleCharacteristic = _bleCharacteristics[id];
    if (bleCharacteristic == null) {
      logw(tag, "未找到写特征 $id");
      return false;
    }

    return _writeData(bleCharacteristic.write, data, withoutResponse: withoutResponse, allowLongWrite: allowLongWrite);
  }

  static Future<bool> _writeData(
    BluetoothCharacteristic? characteristic,
    List<int> data, {
    bool withoutResponse = false,
    bool allowLongWrite = false,
  }) async {
    if (characteristic == null) {
      logw(tag, "写特征为空");
      return false;
    }

    try {
      if (characteristic.properties.write) {
        await characteristic.write(data);
      } else if (characteristic.properties.writeWithoutResponse) {
        await characteristic.write(data, withoutResponse: withoutResponse, allowLongWrite: allowLongWrite);
      } else {
        logw(tag, "写特征不可写");
        return false;
      }
      //logd(tag, "写入成功");
      return true;
    } catch (e) {
      logw(tag, "写入错误: $e");
      return false;
    }
  }

  static Future<List<int>?> _readData(BluetoothCharacteristic? characteristic) async {
    try {
      return characteristic?.read();
    } catch (e) {
      loge(tag, "读取错误: $e");
      return null;
    }
  }

  //uuid匹配
  static bool _uuidMatch(String uuid, {required String full, required String short}) {
    if (uuid.length > 4) {
      if (full.isEmpty) {
        return false;
      }
      return uuid.contains(full);
    } else {
      if (short.isEmpty) {
        return false;
      }
      return uuid.contains(short);
    }
  }

  ///判断是否初始化
  static Future _checkInit() async {
    if (!_initialized) {
      await init();
    }
  }

  ///释放资源
  static void dispose() {
    _initialized = false;
    _isScanning = false;
    _scanResults.clear();
    _bleDiscoveredDevices.clear();
    _bluetoothStateSubscription?.cancel();
    _scanResultsSubscription?.cancel();
    _isScanningSubscription?.cancel();
    _connectionStateSubscriptionMap.forEach((key, value) {
      value.cancel();
    });
    _connectionStateSubscriptionMap.clear();
    _connectedDevices.clear();
    _bleCharacteristics.clear();
    _notifyDataStreamController.close();
    _eventStreamController.close();
  }
}
